#include <u.h>
#include <libc.h>
#include <../boot/boot.h>

/*
 * this is a paqfs version of local.
 */
 
static char diskname[64];
static char *disk;
static char **args;

void
configlocalpaq(Method *mp)
{

//print("configlocalpaq: sys=%s\n", sys);
argv0 = "";
	if(*sys == '/' || *sys == '#'){
		/*
		 *  if the user specifies the disk in the boot cmd or
		 * 'root is from' prompt, use it
		 */
		disk = sys;
	} else if(mp->arg){
		/*
		 *  a default is supplied when the kernel is made
		 */
		disk = mp->arg;
	} else if(*bootdisk){
		/*
		 *  an environment variable from a pc's plan9.ini or
		 *  from the nvram or generated by the kernel
		 *  is the last resort.
		 */
		disk = bootdisk;
	}

	/* if we've decided on one, pass it on to all programs */
	if(disk)
		setenv("bootdisk", disk);

	USED(mp);
}

static char	partition[64];

static int
forkexec(char **execv)
{
	int pid, i, p[2];

	print("%s...", execv[1]);
	if(pipe(p) < 0)
		fatal("pipe");
	switch(pid = fork()){
	case -1:
		fatal("fork");
	case 0:
		dup(p[1], 0);
		dup(p[1], 1);
		close(p[0]);
		close(p[1]);
		exec(execv[0], execv+1);
		fatal("can't exec %s", execv[1]);
	default:
		break;
	}
	for(;;){
		if((i = waitpid()) == -1)
			fatal("waitpid for %s failed", execv[1]);
		if(i == pid)
			break;
	}
	close(p[1]);
	return p[0];
}

#define RAMMNT	"/tmp"
#define PAQF	"/paqfs"

static void
rampart(int partfd)
{
	int mfd, pfd, n, i;
	char *buf;
	char *ramv[] = { "/boot/ramfs", "ramfs", "-i", "-l 64m", 0 };
	enum {
		Nbuf	= 1024*1024,
		Ndot	= (1024*1024)/Nbuf,
	};

	if(stat(ramv[0], statbuf, sizeof statbuf) < 0)
		return;

	mfd = forkexec(ramv);
	if(mfd < 0)
		return;
	if(mount(mfd, -1, RAMMNT, MREPL|MCREATE, "") < 0){
		print("rampart mount fail: %r\n");
		close(mfd);
		return;
	}
	/* mfd is closed by mount */
	pfd = create(RAMMNT PAQF, ORDWR, 0666|OEXCL);
	if(pfd < 0){
		print("rampart create fail: %r\n");
		unmount(0, RAMMNT);
		return;
	}
	buf = malloc(Nbuf);
	if(buf == nil){
		print("rampart malloc fail: %r\n");
		close(pfd);
		return;
	}
	for(i=1;;i++){
		if ((i % Ndot) == 0)
			print(".");
		n = read(partfd, buf, Nbuf);
		if (n <= 0)
			break;
		write(pfd, buf, n);
	}
	free(buf);
	close(pfd);

	snprint(partition, sizeof partition, RAMMNT PAQF);
}

static int
connectpaqfs(void)
{
	int fd, i;
	char *dev;
	char **arg, **argp;

	if(stat("/boot/paqfs", statbuf, sizeof statbuf) < 0)
		return -1;

	dev = disk ? disk : bootdisk;
	snprint(partition, sizeof partition, "%sctl", dev);
	fd = open(partition, OWRITE);
	if(fd >= 0){
		fprint(fd, "dma on\n");
		fprint(fd, "rwm on\n");
		close(fd);
	}

	snprint(partition, sizeof partition, "%sroot", dev);

	fd = open(partition, OREAD);
	if(fd < 0){
		strcpy(partition, dev);
		fd = open(partition, OREAD);
		if(fd < 0)
			return -1;
	}
	rampart(fd);
	close(fd);

	arg = malloc((bargc+8)*sizeof(char*));
	argp = arg;
	*argp++ = "/boot/paqfs";
	*argp++ = "paqfs";
	*argp++ = "-v";
	*argp++ = "-i";
	*argp++ = "-q";
	*argp++ = "-s";
	*argp++ = partition;
	for(i=1; i<bargc; i++)
		*argp++ = bargv[i];
	*argp = 0;

	fd = forkexec(arg);
	free(arg);
	return fd;
}

int
connectlocalpaq(void)
{
	int fd;

	if(bind("#c", "/dev", MREPL) < 0)
		fatal("bind #c");
	if(bind("#p", "/proc", MREPL) < 0)
		fatal("bind #p");
	bind("#S", "/dev", MAFTER);

	if((fd = connectpaqfs()) < 0)
		return -1;
	return fd;
}
